﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Threading;

namespace Pixysoft.DesignPattern
{
    /// <summary>
    /// http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/20289c10-4f95-42af-b993-f6a01da60297
    /// 
    /// http://stackoverflow.com/questions/440016/activator-createinstance-with-private-sealed-class
    /// 
    /// 使用方法：继承Singleton<类名>，
    /// 类名.Instance / Instances["id"]
    /// 
    /// 如果在初始化中就要使用SingletonId，则需要在类中写一个带参数的构造函数,然后再调用
    /// public 类名(string singletonId){}
    /// 
    /// 唯一单例：如果外部调用单例要调用某个初始化构造方法，但是内部调用单例不要，则重载SingleInitialize();
    /// 外部：Instance, 内部_Instance
    /// 案例：NoebeManager.Instance.NoebeCommand会自动启动 SingleInitialize / NoebeManager.Initialize(){_Instance.Initializes();} 则不会
    /// 
    /// 多单例：如果启动多单例要调用初始化方法，则重载MultiInitialize();
    /// 
    /// 其他：如果在类的构造函数中调用了另外的方法，则唯一单例、多单例初始化的时候都会调用。
    /// 
    /// 
    /// 注意：
    /// 调用单例池xxx.Instances[xxx]会默认调用内部单例的MultiInitialize()，这个时候如果这个方法被实现了，就会再次初始化，导致第一次xxx.Instance的初始化被覆盖
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Singleton<T>
    {
        private string _id = null;

        private static volatile SingletonCollection instances;

        private static volatile object instance;

        private static object syncRoot = new Object();



        protected Singleton()
        {
        }

        protected Singleton(string singletonId)
        {
            this._id = singletonId;
        }

        /// <summary>
        /// 调用Instance唯一单例的时候，初始化的时候自动调用；如果是多单例，则不调用
        /// </summary>
        protected virtual void SingleInitialize()
        {
        }

        /// <summary>
        /// 多单例下初始化调用
        /// </summary>
        protected virtual void MultiInitialize()
        {
        }

        /// <summary>
        /// 内部初始化的时候调用，可以绕开上文的Initialize
        /// </summary>
        protected static T _Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            ConstructorInfo nonPublicConstructorInfo =
                               typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null);

                            instance = nonPublicConstructorInfo.Invoke(new object[] { });
                        }
                    }
                }

                return (T)instance;

            }
        }


        /// <summary>
        /// 外部调用的单例
        /// </summary>
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            ConstructorInfo nonPublicConstructorInfo =
                               typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null);

                            object tempinstance = nonPublicConstructorInfo.Invoke(new object[] { });

                            //调用构造函数

                            ((Singleton<T>)tempinstance).SingleInitialize();

                            instance = tempinstance;
                        }
                    }
                }

                return (T)instance;

            }
        }

        /// <summary>
        /// 单例池 
        /// 2009-11-16 注意：不支持冷启动，例如NoebeManager.Instances[xxx] 如果没有配置文件，仍然会报错。
        /// </summary>
        public static SingletonCollection Instances
        {
            get
            {
                if (instances == null)
                {
                    lock (syncRoot)
                    {
                        if (instances == null)
                        {
                            instances = new SingletonCollection(Instance);

                            //使用外部的instance

                            //09-10-27 使用内部的_instance

                            //09-11-02 如果使用内部的instance，调用了单例池之后，调用单例会由于没有初始化而出错
                        }
                    }
                }

                return instances;
            }
        }

        /// <summary>
        /// 同步锁
        /// </summary>
        public static object SyncRoot
        {
            get { return syncRoot; }
        }

        /// <summary>
        /// 单例编号
        /// </summary>
        public string SingletonId
        {
            get { return _id; }
        }

        /// <summary>
        /// 在对象里面取得单例池
        /// </summary>
        /// <param name="singletonId"></param>
        /// <returns></returns>
        public T this[string singletonId]
        {
            get
            {
                return Instances[singletonId];
            }
        }

        /// <summary>
        /// 在对象里面取得单例池
        /// </summary>
        /// <param name="singletonId"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                return Instances[index];
            }
        }



        public class SingletonCollection
        {
            private T instance;

            private Dictionary<string, T> dict = new Dictionary<string, T>();

            internal SingletonCollection(T instance)
            {
                this.instance = instance;
            }

            public T this[string id]
            {
                get
                {
                    //如果是null，表示自己，则直接返回Instance

                    if (string.IsNullOrEmpty(id))
                        return instance;

                    id = id.Trim().ToUpper();

                    if (dict.ContainsKey(id))
                        return dict[id];

                    lock (syncRoot)
                    {
                        if (dict.ContainsKey(id))
                            return dict[id];

                        ConstructorInfo nonPublicConstructorInfo =
                            typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                            null, new Type[] { typeof(string) }, null);

                        object i = null;

                        if (nonPublicConstructorInfo == null)
                        {
                            nonPublicConstructorInfo =
                               typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                               null, new Type[] { }, null);

                            i = nonPublicConstructorInfo.Invoke(new object[] { });
                        }
                        else
                        {
                            i = nonPublicConstructorInfo.Invoke(new object[] { id });
                        }

                        ((Singleton<T>)i)._id = id;

                        ((Singleton<T>)i).MultiInitialize();

                        T it = (T)i;

                        dict.Add(id, it);

                        return it;
                    }

                }
            }

            public T this[int index]
            {
                get
                {
                    if (index < 0 || index > dict.Keys.Count - 1)
                        return instance;

                    int coutner = 0;

                    foreach (string key in dict.Keys)
                    {
                        if (coutner >= index)
                            return dict[key];

                        coutner++;
                    }

                    return instance;

                }
            }
        }
    }
}
